/**
 @file ctc_asw_dma.c

 @author  Copyright (C) 2020 Centec Networks Inc.  All rights reserved.

 @date 2020-06-15

 @version v2.0

 The file contains all dma APIs
*/

/****************************************************************************
*
* Header Files
*
****************************************************************************/
#include "ctc_asw_common.h"
#include "ctc_asw_packet.h"
#include "ctc_pdu.h"
#include "asw/include/drv_api.h"
/****************************************************************************
*
* Defines and Macros
*
*****************************************************************************/

#define CTC_ING_PTAG_PORT_MODE_DOWN 0
#define CTC_ING_PTAG_PORT_MODE_UP 1
#define CTC_PACKET_TX_MAX_PRIORITY 7

#define CTC_ASW_DMA_L2_HDR 12
#define CTC_ASW_PKT_HEADER_LEN    16
#define BIT_OFFSET(x)      (1 << (x))
/****************************************************************************
*
* Global and Declaration
*
*****************************************************************************/
CTC_PKT_RX_CALLBACK dma_rx_cb[CTC_MAX_LOCAL_CHIP_NUM];
uint8 pkt_header[CTC_MAX_LOCAL_CHIP_NUM][CTC_ASW_PKT_HEADER_LEN];

/****************************************************************************
*
*  Functions
*
*****************************************************************************/
static int32
_ctc_asw_byte_reverse_copy(uint8* dest, uint8* src, uint32 len)
{
    uint32 i = 0;
    for (i = 0; i < len; i++)
    {
        *(dest + i) = *(src + (len - 1 - i));
    }
    return 0;
}

static int32
_ctc_asw_packet_encap(uint8 lchip, ctc_pkt_tx_t* p_pkt_tx)
{
    ing_ptag_data_t* p_raw_hdr              = NULL;
    ctc_pkt_info_t* p_tx_info = NULL;

    p_tx_info = &p_pkt_tx->tx_info;
    /* 1. encode packet header */
    if (CTC_FLAG_ISSET(p_tx_info->flags, CTC_PKT_FLAG_ZERO_COPY))
    {
        p_raw_hdr = (ing_ptag_data_t*)(p_pkt_tx->skb.data - CTC_ASW_PKT_HEADER_LEN);
    }
    else
    {
        sal_memset((uint8*)&pkt_header[lchip][0], 0, CTC_ASW_PKT_HEADER_LEN);
        p_raw_hdr = (ing_ptag_data_t*)pkt_header[lchip];
    }

    sal_memmove((uint8*)&p_pkt_tx->skb.data[CTC_ASW_DMA_L2_HDR+CTC_ASW_PKT_HEADER_LEN], (uint8*)&p_pkt_tx->skb.data[CTC_ASW_DMA_L2_HDR], p_pkt_tx->skb.len-CTC_ASW_DMA_L2_HDR);
    p_raw_hdr->opcode = 1;
    p_raw_hdr->ptag_tpid = 0x9100;
    if (CTC_FLAG_ISSET(p_tx_info->flags, CTC_PKT_FLAG_NH_OFFSET_BYPASS))
    {
        p_raw_hdr->bypass_eap = 1;
        p_raw_hdr->bypass_egacl = 1;
        p_raw_hdr->bypass_egloopback = 1;
        p_raw_hdr->bypass_egmeter = 1;
        p_raw_hdr->bypass_egstp = 1;
        p_raw_hdr->bypass_egvlan = 1;
        p_raw_hdr->bypass_inacl = 1;
        p_raw_hdr->bypass_inloopback = 1;
        p_raw_hdr->bypass_inmeter = 1;
        p_raw_hdr->bypass_inprotect = 1;
        p_raw_hdr->bypass_inspmac = 1;
        p_raw_hdr->bypass_instp = 1;
        p_raw_hdr->bypass_invlan = 1;
        p_raw_hdr->bypass_isvid = 1;
        p_raw_hdr->bypass_learning = 1;
        p_raw_hdr->not_modify = 1;
    }

    if (CTC_FLAG_ISSET(p_tx_info->flags, CTC_PKT_FLAG_SRC_PORT_VALID))
    {
        p_raw_hdr->port_mode = CTC_ING_PTAG_PORT_MODE_UP;
        p_raw_hdr->port_bitmap_l = p_tx_info->src_port;
    }
    else
    {
        p_raw_hdr->port_mode = CTC_ING_PTAG_PORT_MODE_DOWN;
        p_raw_hdr->inservice_meter_id = (BIT_OFFSET(p_tx_info->dest_gport) >> 18) & 0x7FF;
        p_raw_hdr->inservice_meter_dir = (BIT_OFFSET(p_tx_info->dest_gport) >> 17) & 0x1;
        p_raw_hdr->port_bitmap_l = (BIT_OFFSET(p_tx_info->dest_gport)) & 0x1FFFF;
    }

    p_raw_hdr->fid = p_tx_info->fid;
    if (CTC_FLAG_ISSET(p_tx_info->flags, CTC_PKT_FLAG_PRIORITY))
    {
        p_raw_hdr->qpdp = p_tx_info->priority;
        p_raw_hdr->use_this_qpdp = 1;
    }
    _ctc_asw_byte_reverse_copy((uint8*)&p_pkt_tx->skb.data[CTC_ASW_DMA_L2_HDR], (uint8*)p_raw_hdr, CTC_ASW_PKT_HEADER_LEN);

    /*policer*/
    /*p_raw_hdr->inservice_meter_dir = ;
    p_raw_hdr->inservice_meter_id = ;
    p_raw_hdr->inservice_meter_mode = ;*/


    return CTC_E_NONE;
}

static int32
_ctc_asw_packet_decap(uint8 lchip, ctc_pkt_rx_t* p_pkt_rx)
{
    eg_ptag_data_t raw_hdr;
    eg_ptag_data_t* p_raw_hdr = &raw_hdr;
    ctc_pkt_info_t* p_rx_info = NULL;

    _ctc_asw_byte_reverse_copy((uint8*)p_raw_hdr,  (uint8*)&p_pkt_rx->pkt_buf[0].data[CTC_ASW_DMA_L2_HDR], CTC_ASW_PKT_HEADER_LEN);
    p_rx_info = &p_pkt_rx->rx_info;
    sal_memset(p_rx_info, 0, sizeof(ctc_pkt_info_t));

    CTC_SET_FLAG(p_rx_info->flags, CTC_PKT_FLAG_PRIORITY);
    CTC_SET_FLAG(p_rx_info->flags, CTC_PKT_FLAG_COLOR);
    p_rx_info->color = p_raw_hdr->local_color;
    p_rx_info->priority = p_raw_hdr->local_pri;
    p_rx_info->dest_gport = p_raw_hdr->dport_bitmap_26_20_0 | (p_raw_hdr->dport_bitmap_26_25_21<<21) | ((p_raw_hdr->cnt_index&0x7)<<26);

    CTC_SET_FLAG(p_rx_info->flags, CTC_PKT_FLAG_SRC_SVID_VALID);
    p_rx_info->src_svid = p_raw_hdr->internal_svid_12_0_0 | (p_raw_hdr->internal_svid_12_11_1<<1);
    p_rx_info->src_port = p_raw_hdr->src_port_6_1_0 | (p_raw_hdr->src_port_6_5_2<<2);
    /*if (p_raw_hdr->not_learning)
    {
        CTC_SET_FLAG(p_rx_info->flags, CTC_PKT_FLAG_NOT_LEARN);
    }*/
    p_rx_info->packet_type = p_raw_hdr->layer_type;
    p_rx_info->ctag_op = p_raw_hdr->itag_action;
    p_rx_info->stag_op = p_raw_hdr->otag_action;
    if (p_raw_hdr->acl_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_ACL_MATCH;
    }
    else if (p_raw_hdr->arl_cpucopy)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_FWD_CPU;
    }
    else if (p_raw_hdr->ingmir_tocpu || p_raw_hdr->egmir_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_MIRRORED_TO_CPU;
    }
    else if (p_raw_hdr->ivt_chk_fail_tocpu || p_raw_hdr->ivt_unknown_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_DROP;
    }
    else if (p_raw_hdr->pmac_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_L2_PDU;
    }
    else if (p_raw_hdr->smac_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_L2_PDU+CTC_L2PDU_ACTION_INDEX_FIP+1;
    }
    else if (p_raw_hdr->ip_have_option)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_L3_IP_OPTION;
    }
    else if (p_raw_hdr->cpu_ptag_tocpu)
    {
        p_rx_info->reason = CTC_PKT_CPU_REASON_C2C_PKT;
    }

    return CTC_E_NONE;
}

int32
ctc_asw_packet_init(uint8 lchip, void* p_global_cfg)
{

    return CTC_E_NONE;
}

int32
ctc_asw_packet_deinit(uint8 lchip)
{

    return CTC_E_NONE;
}

int32
ctc_asw_packet_encap(uint8 lchip, ctc_pkt_tx_t* p_pkt_tx)
{
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(p_pkt_tx);
    CTC_PTR_VALID_CHECK(p_pkt_tx->skb.data);
    CTC_API_LOCK(lchip);
    ret = _ctc_asw_packet_encap(lchip, p_pkt_tx);
    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_packet_decap(uint8 lchip, ctc_pkt_rx_t* p_pkt_rx)
{
    int32 ret = CTC_E_NONE;

    CTC_PTR_VALID_CHECK(p_pkt_rx);
    CTC_PTR_VALID_CHECK(p_pkt_rx->pkt_buf);
    CTC_API_LOCK(lchip);
    ret = _ctc_asw_packet_decap(lchip, p_pkt_rx);
    CTC_API_UNLOCK(lchip);

    return ret;
}
